package com.nbcio.modules.erp.coderule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.nbcio.modules.erp.coderule.domain.ErpCodeRule;
import com.nbcio.modules.erp.coderule.mapper.ErpCodeRuleMapper;
import com.nbcio.modules.erp.coderule.service.ICodeRuleService;
import com.nbcio.modules.erp.doc.domain.ErpBill;
import com.nbcio.modules.erp.doc.mapper.ErpBillMapper;
import com.nbcio.modules.erp.voucher.domain.ErpVoucher;
import com.nbcio.modules.erp.voucher.mapper.ErpVoucherMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 编码规则服务实现
 */
@Slf4j
@Service
public class CodeRuleServiceImpl implements ICodeRuleService {

    @Resource
    private ErpCodeRuleMapper codeRuleMapper;
    
    @Resource
    private ErpBillMapper billMapper;
    
    @Resource
    private ErpVoucherMapper voucherMapper;

    @Override
    public String nextBillNo(String billType) {
        log.info("生成单据号，billType: {}", billType);
        
        // 查询规则配置
        ErpCodeRule rule = codeRuleMapper.selectOne(
                new LambdaQueryWrapper<ErpCodeRule>()
                        .eq(ErpCodeRule::getBizType, billType)
                        .eq(ErpCodeRule::getEnableFlag, 1)
                        .last("LIMIT 1"));
        
        if (rule == null || rule.getPattern() == null || rule.getPattern().isEmpty()) {
            // 如果没有配置规则，使用默认规则：{BIZ}-{YYYYMMDD}-{SEQ}
            log.warn("未找到 billType={} 的编码规则，使用默认规则", billType);
            return generateDefaultBillNo(billType);
        }
        
        log.info("找到编码规则，pattern: {}, seqLen: {}, resetPeriod: {}", 
                rule.getPattern(), rule.getSeqLen(), rule.getResetPeriod());
        
        // 解析模板并生成单据号
        String billNo = generateBillNoByRule(rule, billType);
        log.info("生成单据号结果: {}", billNo);
        return billNo;
    }
    
    /**
     * 默认规则生成：{BIZ}-{YYYYMMDD}-{SEQ}
     */
    private String generateDefaultBillNo(String billType) {
        LocalDate today = LocalDate.now();
        String date = today.format(DateTimeFormatter.BASIC_ISO_DATE); // yyyyMMdd
        String prefix = billType + "-" + date + "-";
        
        Long count;
        if ("VOUCHER".equals(billType)) {
            // 凭证号查询凭证表
            count = voucherMapper.selectCount(Wrappers.<ErpVoucher>lambdaQuery()
                    .like(ErpVoucher::getVoucherNo, prefix));
        } else {
            // 单据号查询单据表
            count = billMapper.selectCount(Wrappers.<ErpBill>lambdaQuery()
                    .eq(ErpBill::getBillType, billType)
                    .like(ErpBill::getBillNo, prefix));
        }
        long seq = (count == null ? 0 : count) + 1;
        
        String billNo = prefix + String.format("%04d", seq);
        log.info("默认规则生成单据号: {}", billNo);
        return billNo;
    }
    
    /**
     * 根据规则生成单据号
     */
    private String generateBillNoByRule(ErpCodeRule rule, String billType) {
        String pattern = rule.getPattern();
        LocalDate today = LocalDate.now();
        
        // 先替换日期相关变量，用于计算序号前缀
        String prefixPattern = pattern;
        prefixPattern = prefixPattern.replace("{BIZ}", billType);
        prefixPattern = prefixPattern.replace("{YYYY}", today.format(DateTimeFormatter.ofPattern("yyyy")));
        prefixPattern = prefixPattern.replace("{YY}", today.format(DateTimeFormatter.ofPattern("yy")));
        prefixPattern = prefixPattern.replace("{MM}", today.format(DateTimeFormatter.ofPattern("MM")));
        prefixPattern = prefixPattern.replace("{DD}", today.format(DateTimeFormatter.ofPattern("dd")));
        prefixPattern = prefixPattern.replace("{YYYYMMDD}", today.format(DateTimeFormatter.BASIC_ISO_DATE));
        prefixPattern = prefixPattern.replace("{YYYYMM}", today.format(DateTimeFormatter.ofPattern("yyyyMM")));
        
        // 计算序号前缀（去掉序号部分）
        String resetPrefix = calculateResetPrefix(rule, billType, prefixPattern);
        log.debug("计算序号前缀，resetPrefix: {}", resetPrefix);
        
        // 查询符合重置前缀的单据/凭证数量
        Long count;
        if ("VOUCHER".equals(billType)) {
            // 凭证号查询凭证表
            count = voucherMapper.selectCount(Wrappers.<ErpVoucher>lambdaQuery()
                    .like(ErpVoucher::getVoucherNo, resetPrefix));
        } else {
            // 单据号查询单据表（同时按 billType 筛选，确保不混用）
            count = billMapper.selectCount(Wrappers.<ErpBill>lambdaQuery()
                    .eq(ErpBill::getBillType, billType)
                    .like(ErpBill::getBillNo, resetPrefix));
        }
        log.debug("查询到符合前缀的单据/凭证数量: {}", count);
        long seq = (count == null ? 0 : count) + 1;
        
        // 替换模板变量（完整替换，包括序号）
        String result = pattern;
        result = result.replace("{BIZ}", billType);
        result = result.replace("{YYYY}", today.format(DateTimeFormatter.ofPattern("yyyy")));
        result = result.replace("{YY}", today.format(DateTimeFormatter.ofPattern("yy")));
        result = result.replace("{MM}", today.format(DateTimeFormatter.ofPattern("MM")));
        result = result.replace("{DD}", today.format(DateTimeFormatter.ofPattern("dd")));
        result = result.replace("{YYYYMMDD}", today.format(DateTimeFormatter.BASIC_ISO_DATE));
        result = result.replace("{YYYYMM}", today.format(DateTimeFormatter.ofPattern("yyyyMM")));
        
        // 替换序号
        int seqLen = rule.getSeqLen() != null && rule.getSeqLen() > 0 ? rule.getSeqLen() : 4;
        String seqStr = String.format("%0" + seqLen + "d", seq);
        result = result.replace("{SEQ}", seqStr);
        
        return result;
    }
    
    /**
     * 根据重置周期计算查询前缀（用于统计序号）
     */
    private String calculateResetPrefix(ErpCodeRule rule, String billType, String fullPrefix) {
        String resetPeriod = rule.getResetPeriod() != null ? rule.getResetPeriod() : "DAILY";
        LocalDate today = LocalDate.now();
        
        // 找到 {SEQ} 的位置
        int seqIndex = fullPrefix.indexOf("{SEQ");
        if (seqIndex < 0) {
            // 如果没有序号占位符，返回完整前缀
            return fullPrefix.substring(0, fullPrefix.length() - 4); // 假设最后4位是序号
        }
        
        // 序号前的部分作为前缀
        String basePrefix = fullPrefix.substring(0, seqIndex);
        
        switch (resetPeriod) {
            case "MONTHLY":
                // 按月重置：保留到年月部分
                // 如果前缀已包含年月格式（如 PO_IN-202501），直接使用
                if (basePrefix.matches(".*\\d{6}.*")) {
                    return basePrefix;
                }
                // 否则添加年月：{BIZ}-{YYYYMM}-
                return billType + "-" + today.format(DateTimeFormatter.ofPattern("yyyyMM")) + "-";
            case "YEARLY":
                // 按年重置：保留到年份部分
                if (basePrefix.matches(".*\\d{4}.*")) {
                    return basePrefix;
                }
                return billType + "-" + today.format(DateTimeFormatter.ofPattern("yyyy")) + "-";
            case "NEVER":
                // 永不重置：只按业务类型
                return billType + "-";
            case "DAILY":
            default:
                // 按日重置（默认）：使用完整前缀（包含日期）
                return basePrefix;
        }
    }
}


